import json
import os

from loguru import logger
from typing import  List

from app.common.exception import errors
from app.common.exception.agv import AGVError
from app.core.conf import ST
from app.crud import crud_task
from app.database.db_sqlite import async_db_session
from app.models.Task import Task
from app.models.user import User
from app.schemas.task import RQTaskSleepTime, RQUpdateTask, RSTask,RQTask,StationInfo,DAOCreateTask,RQRunTask
from app.utils.generate_string import get_cur_timestamp
from app.core.conf import ST
from app.sio_agv.agv_socket import AGV
# from sio_agv.agv_socket import AGV

# ============================================================================================
async def get_tasks(current_user: User)->List[RSTask]:
    """获取所有的任务链，以站点和暂停时间返回
    Returns:
        List[RSTask]: _description_
    """
    async with async_db_session.begin() as db:
        tasks:List[Task] = await crud_task.get_all_task(db)
        new_tasks = []
        for task in tasks:
            new_task = handle_task_info(task)
            if new_task is None:
                # 没有读取到该任务的json文件，所以要从数据库中删除其信息
                await crud_task.delete_task_by_task_name(db,task.task_name)
                continue
            new_tasks.append(new_task)
        return new_tasks

def handle_task_info(task:Task):
    data_json = read_task_json(task.task_name)
    if data_json is None:
        logger.warning(f'当前任务{task.name}的json文件不存在');
        logger.warning(task.task_name);
        return None
    station_list = unpack_task(data_json)
    rs_task =  RSTask(id=task.id,name=task.name,task_name=task.task_name,task_list=station_list)
    return rs_task


def read_task_json(task_name:str):
    try:
        with open(os.path.join(ST.TASK_PATH,f'{task_name}.json'),'r',encoding='utf-8') as f:
            data = json.load(f)
            return data
    except Exception as e:
        logger.debug('读取任务链json错误，不存在该任务');
        return None
    
def unpack_task(task_obj):
    task_list = []
    for action_obj in task_obj.get('tasks')[0].get('actionGroups'):
        task_list.append({
            "station":action_obj.get('actions')[0].get('params')[1].get('stringValue'),
            "sleep_time":action_obj.get('actions')[0].get('sleepTime')
        })
    return task_list

# ============================================================================================
async def create_task(obj:RQTask):
    """创建任务
    Args:
        obj (RQTask): _description_
    Raises:
        errors.HTTPError: _description_
        errors.HTTPError: _description_
    """
    async with async_db_session.begin() as db:
        # 生成唯一的任务名称,也可以认为是id
        task_name = "task_{timestamp}".format(timestamp=get_cur_timestamp())
        # 如果不保存
        if not obj.is_save:
            if obj.is_run:
                # 直接去创建任务链，然后执行就好了
                handle_req_task_info(obj,task_name)
            else:
                raise errors.HTTPError(msg='任务不执行，不保存')
        task = await crud_task.get_task_by_name(db,obj.name)
        if task:
            raise errors.HTTPError(msg='任务名称重复')
        # 存储到数据库中
        await crud_task.create_task(db,DAOCreateTask(name=obj.name,task_name=task_name))
        handle_req_task_info(obj,task_name)


def handle_req_task_info(obj:RQTask,task_name:str):
    task_dict = pack_task(obj.task_list,task_name,obj.is_loop) 
    if obj.is_save:
        save_task_json(task_name,task_dict)
    if obj.is_run:
        execute_task(task_dict)

def save_task_json(task_name,task_dict):
    with open(os.path.join(ST.TASK_PATH,f'{task_name}.json'),'w') as f:
        json.dump(task_dict,f)

def execute_task(task_dict):
    tt15 = AGV.get_agv(ST.AGV1_IP)
    tt15.send('nav',1,3100,task_dict)
    res = tt15.receive('nav')
    if res.get('ret_code'):
        raise AGVError(res)

def pack_task(task_list:List[StationInfo],task_name,is_loop:False):
    actionGroups = []
    for index,action in enumerate(task_list):
        actionGroups.append({
            "actions": [
                {
                    "actionName": "move_action",
                    "pluginName": "MoveFactory",
                    "params": [
                        {
                            "key": "skill_name",
                            "stringValue": "GotoSpecifiedPose"
                        },
                        {
                            "key": "target_name",
                            "stringValue": action.station 
                        }
                    ],
                    "ignoreReturn": False,
                    "overtime": 0,
                    "externalOverId": -1,
                    "needResult": False,
                    "sleepTime": action.sleep_time,
                    "actionId": 0
                }
            ],
            "actionGroupName": "group {idx}".format(idx = index+1),
            "actionGroupId": index,
            "checked": True
        })
    
    tasks = []
    tasks.append({
        "taskId":0,
        "desc":"",
        "actionGroups":actionGroups,
        "checked":True
    })
    task_obj = {
        "name":task_name,
        "tasks":tasks,
        "loop":is_loop
    }
    return task_obj

# ===========================================================================================================================

async def del_task(task_name:str):
    """删除任务
    Args:
        task_name (str): _description_
    """
    async with async_db_session.begin() as db:
        await crud_task.delete_task_by_task_name(db,task_name)
        file_path = os.path.join(ST.TASK_PATH,f'{task_name}.json')
        if os.path.exists(file_path):
            os.remove(file_path)
            raise errors.HTTPError(msg='删除成功,json文件不存在')


# ===========================================================================================================================
async def run_task(params:RQRunTask):
    """执行已经预先保存好的任务
    Args:
        params (RQRunTask):  执行任务的参数 
    Raises:
        errors.HTTPError: _description_
    """
    data_json = read_task_json(params.task_name)
    if data_json is None:
        raise errors.HTTPError(msg=f'当前导航{params.name}json丢失，请删除重新创建')
    execute_task(data_json)

# =========================修改任务的名称=================================================================================================
async def update_task(obj:RQUpdateTask):
    async with async_db_session.begin() as db:
        res = await crud_task.update_task_user_name_by_id(db,obj.id,obj.name)
        return res

# ==========================================================================================================================

async def update_task_sleep_time(obj:RQTaskSleepTime):
    file_path = os.path.join(ST.TASK_PATH,f'{obj.task_name}.json')
    if not os.path.exists(file_path):
        raise errors.HTTPError(msg='失败:json文件不存在')
    old_json = read_task_json(obj.task_name)
    task_dict = pack_task(obj.task_list,obj.task_name,old_json.get('loop')) 
    os.remove(file_path)
    save_task_json(obj.task_name,task_dict)

# ==========================================================================================================================

